

import serial
import math
from time import sleep

import xlrd
import time
import sys

import winsound

import datetime


from DataConvert.DataConvert import *
from Uart.SerialHelper import *



# import sys
# sys.path.append('E:\_code\python\test1')
# from DataChange import *


COMX_temp='com10'


import logging
import logging.config
from os import path
config_log='../LogConfig/logger.conf'

def profile_demand(dataget,_offset=0):
    #print('demand~~\n',dataget)
    if(len(dataget)<10 or len(dataget)<_offset  ):
        return ''
    if(dataget[:_offset]!=b'\x02\x28\x30\x36\x29\x03\x04'):
        return''

    _year=Hex2bcd(dataget[_offset]+0)+2000
    _month=Hex2bcd(dataget[_offset+1])
    _day=Hex2bcd(dataget[_offset+2])
    _hour=Hex2bcd(dataget[_offset+3])
    _minitue=Hex2bcd(dataget[_offset+4])
    d_begin = datetime.datetime(_year, _month, _day,_hour,_minitue)
    #print(d_begin.strftime('%Y-%m-%d %H:%M'))
    _offset+=5
    lenlist=[3]
    p=_offset
    _time=d_begin
    ret='Here is the profile text \n'
    count=0
    for j in range(int((len(dataget)-_offset)/3)):
        for i in lenlist:
            t = dataget[p:(p + i)]
            s = str(hex(t[0])).replace('0x', '') + '.' + str(hex(t[1])).replace('0x', '') + str(hex(t[2])).replace('0x', '')
            s=_time.strftime('%Y-%m-%d %H:%M')+'~  ~'+s
            _time = _time +datetime.timedelta(minutes=-15)
            p += i
            ret+=s+'\n'
            count+=1
            #print(s)
    ret+='there are %s num '%count
    return ret




class Iec21Com(SerialHelper):

    def __init__(self,port='com1',bps_before='4800',ByteSize="8", Parity="N", Stopbits="1",
                 bps_after='9600',bps_change=True,password='00000000',wait=1.5):

        SerialHelper.__init__(self,Port=port, BaudRate=bps_before,ByteSize=ByteSize,Parity=Parity,Stopbits=Stopbits,wait=wait)

        self.bps_change=bps_change
        self.bps_after=bps_after
        self.password=password
        self._serial = None
        self._is_connected = False

        self.iec_sta_idle='iec_sta_idle'
        self.iec_sta_hand='iec_sta_hand'
        self.iec_sta_passwordcheck='iec_sta_passwordcheck'
        self.iec_sta_bpschange='iec_sta_bpschange'
        self.iec_sta_wr='iec_sta_wr'
        self.iec_sta_err='self.iec_sta_err'

        self.iecsta=self.iec_sta_idle

        logging.config.fileConfig(config_log)
        self.Log_Iec21Com=logging.getLogger("iec21")

    def send(self,buf,msg=None):
        if msg is not None:
            self.Log_Iec21Com.info(msg)
        self.write(buf)
    def receive(self,msg=None):
        data=self.readall()
        if(data):
            if msg is not None:
                self.Log_Iec21Com.info(msg)
        return data

    def CloseIec21(self):
        buf='\x01\x42\x30\x03\x71'
        self.send(buf.encode(),'->发送b0q：')
        uart_get = self.receive()
        if uart_get:
            self.Log_Iec21Com.warning('->quit：' + uart_get.decode())
        self._serial.close()

    def Hand(self,id='',op=True):

        if(op==True):
            self.connect()
            self.CloseIec21()
            self.connect()
            self.iecsta = self.iec_sta_idle

        if self.iecsta!=self.iec_sta_idle:
            self.iecsta = self.iec_sta_err
            return False
        buf = '/?' + id + '!' + '\r\n'
        self.send(buf.encode(),'->发送握手：'+buf[:-2])
        uart_get=self.receive()
        if(len(uart_get)>5):
            next_baund=uart_get[5]-ord('0')
            ##这里表有bug 好无奈
            self.Log_Iec21Com.info('<-收到响应：'+uart_get[:-2].decode()+'  Meter 支持切换最大波特率'+str(300*math.pow(2,next_baund)))
            self.iecsta=self.iec_sta_hand
            return True
        elif(len(uart_get)):
            self.Log_Iec21Com.warning('收到错误帧' + uart_get.decode())
        else:
            self.Log_Iec21Com.warning('没有收到帧' )
        self.iecsta = self.iec_sta_err


        return False

    def ChangeBps(self,op='\x31'):
        if(self.bps_change==False):
            self.iecsta = self.iec_sta_bpschange
            return True
        i = int(math.log(int(self.bps_after) / 300, 2))
        buf = '\x06\x30' + str(i) +'1\r\n'
        self.send(buf.encode(),'->pc选择波特率'+str(self.bps_after)+ '发送波特率切换帧')
        sleep(0.2)#0.1的时候有表收不到
        self._serial.baudrate = str(self.bps_after)
        uart_get = self.receive()
        if uart_get:
            self.Log_Iec21Com.info('<-应答接收(新bps)：'+ uart_get.decode())
            self.iecsta = self.iec_sta_bpschange
            return True
        else:
            self.Log_Iec21Com.warning('bps切换无应答：' + uart_get.decode())
        self.iecsta = self.iec_sta_err
        return False

    def PasswordCheck(self,password=None):
        if(self.bps_change==False and  self.iecsta == self.iec_sta_bpshand) or self.iecsta == self.iec_sta_bpschange :
            pass
        else:
            self.iecsta = self.iec_sta_err
            return False
        if password ==None:
            password=self.password
        buf='\x01\x50\x31\x02\x28'+password+'\x29\x03\x61'
        self.send(buf.encode(),'->发送(密码)：'+ buf)
        uart_get = self.receive()
        if uart_get:
            if uart_get[0]==6 and len(uart_get)==1:
                self.Log_Iec21Com.info('->password ok：'+uart_get.decode())
                self.iecsta = self.iec_sta_passwordcheck
                return True
        self.Log_Iec21Com.warning('密码有误：' + uart_get.decode())
        self.iecsta = self.iec_sta_err
        return False

    def start(self,id='',password=None):
        self.Hand(id=id)
        self.ChangeBps()
        self.PasswordCheck(password=password)


    def _ReadObis(self,_obis,_wait=2.0,_charwait=0.002,_fun=None,_arg='',printpoint=False):
        if(self.iecsta != self.iec_sta_passwordcheck) and self.iecsta != self.iec_sta_wr :
            self.iecsta = self.iec_sta_err
            return False
        else:
            self.iecsta = self.iec_sta_wr
        buf=str2hexs('01 52 31 02 ')+str2bytes(_obis.upper())+str2hexs('28 29 03 ')
        checknum = bcc(buf[1:])
        buf += bytes((checknum,))
        self.send(buf,'->发送obis：'+_obis)

        lastnum, nownum = (0, 0)
        start, last_time, now_time = (0, 0, 0)
        loadcnt=0
        while True:
            if self._is_connected:
                try:
                    nownum = self._serial.inWaiting()
                    if (nownum > lastnum):
                        last_time = time.clock()
                        if (lastnum == 0):  # fram time rec
                            start = time.clock()
                        lastnum=nownum

                        if(printpoint==True):
                            sys.stdout.write('.')
                            loadcnt+=1
                            if(loadcnt>20):
                                loadcnt=0
                                sys.stdout.write('\b')
                                sys.stdout.write('\n')
                            sys.stdout.flush()
                    else:
                        pass
                    sleep(_charwait)

                    now_time = time.clock()

                    if (abs(now_time - last_time) > self.calc_delay()):
                        pass
                    if (abs(now_time - last_time) > _wait):
                        if(nownum>0):
                            if (printpoint == True):
                                sys.stdout.write('\n')
                                sys.stdout.flush()
                            uart_get = self.read(nownum)
                            break
                except Exception as e:
                    self._is_connected = False
                    break

        if(len(uart_get)):
            if _fun is not  None:
                self.Log_Iec21Com.info(_fun(uart_get,_arg))
            return _obis,uart_get
        else:
            self.Log_Iec21Com.error('no date receive')
            for _ in range(2):
                winsound.Beep(1600, 500)
                sleep(1.5)
                pass
            return _obis, None

    def ReadObis(self,obis,wait=2.0,fun=None,arg='',printon=False):
        a=list()

        i=0
        if isinstance(obis,list):
            for o in obis:
                #a.append([])
                data=self._ReadObis(o,_wait=wait,_fun=fun,_arg=arg)
                a.append(data)
                i += 1
        elif isinstance(obis,str):
            a=self._ReadObis(obis, _wait=wait, _fun=fun, _arg=arg)
        else:
            print(obis)
            print(type(obis))
            self.Log_Iec21Com.error('obis is err type')
        if (printon==True):
            print(a)
        return a

    def _WriteObis(self, _obis, data='',ishex=None, _fun=None, _arg=''):
        self.iecsta = self.iec_sta_wr
        char_b=''
        if isinstance(data, str):
            send_data = str2bytes(data.upper())
            show_data = data
        elif isinstance(data, bytes):
            send_data = data
            show_data = data.decode()

        if(ishex==None):#b'01 25 34 82 ' 直接就是hex
            if isinstance(data, bytes):
                send_data = str2hexs(show_data)
                char_b='hex:\''
        else:
            if(ishex==True):
                send_data=str2hexs(show_data)
                char_b = 'hex:\''

        buf = str2hexs('01 57 31 02 ') + str2bytes(_obis.upper()) + str2hexs('28')+send_data+str2hexs('29 03')
        checknum = bcc(buf[1:])
        buf += bytes((checknum,))
        self.send(buf,'->发送obis+data：'+_obis+'('+char_b+show_data+')')
        uart_get = self.receive()
        if uart_get:
            if len(uart_get)==1:
                if uart_get[0] == 6:
                    self.Log_Iec21Com.info('->Write ok：'+uart_get.decode())
                    return True
                elif uart_get[0] == 0x15:
                    self.Log_Iec21Com.warning('->Write no access：' + uart_get.decode())
                else:
                    self.Log_Iec21Com.warning('->Write err respond：' + uart_get.decode())
            elif len(uart_get):
                self.Log_Iec21Com.warning('->Write err respond：' + uart_get.decode())
            else:
                self.Log_Iec21Com.warning('->Write no respond：')
        return False

    def WriteObis(self,obis_list,ishex=None, _fun=None, _arg=''):
        if isinstance(obis_list, (list,tuple)):
            for o in obis_list:
                if isinstance(o, (list,tuple)) :
                    if len(o) >= 2:
                        if isinstance(o[0], (str,bytes,bytearray)):
                            self._WriteObis(_obis=o[0], data=o[1], ishex=ishex, _fun=_fun, _arg=_arg)

    def date(self,d):
        try:
            ret = datetime.datetime(2000 + int(d[0:2]), int(d[2:4]), int(d[4:6])).strftime("%y%m%d0%w");
        except:
            ret = d
            self.Log_Iec21Com.warning('datetime err ')
        finally:
            return ret





import tkinter.messagebox
from tkinter import *







class func_test(Iec21Com):
    def __init__(self,port='com1',bps_before='4800',bps_after='9600',wait=1.5,uobis='1.8.0',):
        Iec21Com.__init__(self,port=port, bps_before=bps_before, bps_after=bps_after, wait=1, ByteSize="7", Parity="E", )
        self.obis=uobis
    def loop(self,):
        a=0
        for _ in range(1000):
            if(a==0):
                a=1
                self.start()
            else:
                self.ReadObis(obis=self.obis, wait=0.5, printon=True)


if __name__ == '__main__':

    # u = Iec21Com(port='com2', bps_before='300', bps_after="9600", wait=1, ByteSize="7", Parity="E", )
    # u.start()
    # print(u.ReadObis(obis='1.8.0', wait=0.5))
    # for _ in range(12):
    #     print(u.ReadObis(obis='15.29.7', wait=0.5))

    # u0 = func_test(port='com2', bps_before='300', bps_after="9600", wait=1,  )
    # u1 = func_test(port='com8', bps_before='300', bps_after="2400", wait=1, )

    c1=func_test(port='com2', bps_before='300', bps_after="9600",uobis='1.8.0')
    c2=func_test(port='com4', bps_before='300', bps_after="4800",uobis='2.8.0')
    c3=func_test(port='com8', bps_before='300', bps_after="2400",uobis='3.8.0')


    thread_list = []
    t1 = threading.Thread(target=c1.loop)
    t2 = threading.Thread(target=c2.loop)
    t3 = threading.Thread(target=c3.loop)
    thread_list.append(t1)
    thread_list.append(t2)
    thread_list.append(t3)

    for t in thread_list:
        # t.setDaemon(True)  # 设置为守护线程
        t.start()
        # t.join()  # 在这个子线程完成运行之前，主线程将一直被阻塞

    for t in thread_list:
        t.join()  # 在这个子线程完成运行之前，主线程将一直被阻塞

    c1.CloseIec21()
    c2.CloseIec21()
    c3.CloseIec21()



    # t1 = threading.Thread(target=u0.loop(_obis='1.8.0'), name='1')
    # # t2 = threading.Thread(target=u1.loop(_obis='2.8.0'), name='1')
    # t2 = threading.Thread(target=u3.lo, name='2')
    #
    # t1.setDaemon(True)
    # t2.setDaemon(True)
    # t1.start()
    # t2.start()





    # obislist=['1.8.0','2.8.0','3.8.0','4.8.0','5.8.0','6.8.0','7.8.0','8.8.0','11.8.0']
    #print('---------------------------')
    # print(u.ReadObis(obis='11.8.0.0', wait=0.5))
    # print(u.ReadObis(obis='5.8.0', wait=0.5))
    # print(u.ReadObis(obis='8.8.0', wait=0.5))
    # for i in range(13):
    #     print(u.ReadObis(obis='11.8.0.'+str(i), wait=0.5))
    # print(u.ReadObis(obis='11.8.0.1', wait=0.5))


    #print('close')
    # while(1):
    #     pass
    #
    # while 1 :
    #     errcount=0
    #     b=0
    #     while 1:
    #
    #         b+=1
    #         if(b>4):
    #             b=0
    #         bpslist=[300,1200,2400,4800,9600]
    #
    #         print('errcount= ',errcount)
    #         u=Iec21Com(port='com4',bps_before='300',bps_after=str(bpslist[b]),wait=1,ByteSize="7", Parity="E",)
    #         #u.start()
    #         print("------------------")
    #         u.Hand()
    #
    #         i = int(math.log(int(u.bps_after) / 300, 2))
    #         buf = '\x06\x30' + str(i) + '0\r\n'
    #         u.send(buf.encode())
    #         print( '->pc选择波特率' + str(u.bps_after) + '发送波特率切换帧')
    #
    #         #u.send(b'\x06040\x0d\x0a')
    #         sleep(0.2)
    #         u._serial.baudrate=u.bps_after
    #         temp=u.receive()
    #
    #         if(len(temp)>10):
    #             checknum = bcc(temp[1:-1])
    #             print("len=",len(temp),'   ',showhexs(temp[-10:]))
    #             if(checknum==temp[-1]):
    #                 print("yes")
    #                 continue
    #
    #         print("No")
    #         winsound.Beep(1600, 500)
    #         errcount+=1
    #
    #
    #
    #
    #
    # #读取obis测试
    # if 0:
    #     u = Iec21Com(port='com1', bps_before='300', bps_after='9600', wait=1, ByteSize="7", Parity="E", )
    #     u.start()
    #     while 1:
    #         print(u.ReadObis(obis='0.9.1'))



    #u._WriteObis(_obis='0.9.1',data='182042')
    # u._WriteObis(_obis='0.9.2', data=u.date('18110605'))
    # print(u.ReadObis('0.9.1'))
    # print(u.ReadObis('0.9.2'))








    #tkinter.messagebox.showinfo("FishC Demo", "2017新年快乐")
    # a = u.ReadObis(['1.8.0','2.8.0','3.8.0','4.8.0','15.8.0'], wait=1.0)
    # for i in a:
    #     print(i)

    # for i in range(1):
    #     #start = time.clock()
    #
    #     a=u.ReadObis('0.0.0',wait=1.0)
    #     print(a)
    #
    #     if(u.ReadObis('0.0.0',wait=1.0)):
    #         pass
    #     else:
    #         print('999999999999999999999999999999999999999999  i=%05d      9999999999999999999999999999999' %i)
    #     print('88888888888888  i=%05d      88888888888888888888' %i)
    #     #end = time.clock()
    #     #print(end - start)
    #sleep(1)
    #u.CloseIec21()






